package com.xpec.c4.game.common;

import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GUIDFactory;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.contexts.Contexts;
import com.xpec.c4.service.group.transportlayer.GroupMessage;
import com.xpec.c4.service.message.MessageAction;

/**
 * 产生验证码
 * 
 * @author lipeilin
 * @2010-9-11下午03:39:51
 * 
 */
public class LoginVerifyCodeManager {

	/**
	 * 
	 */
	private static final Log log = LogFactory
			.getLog(LoginVerifyCodeManager.class);

	/**
	 * 
	 */
	private long lifespan = 10 * 60* 1000;
	
	/**
	 * 
	 */
	public static final int  CREATE_VERIFYCODE_PUT_LOCAL = 1;
	
	/**
	 * 
	 */
	public static final int  CREATE_VERIFYCODE_NOT_PUT_LOCAL = 2;
	
	/**
	 * 验证码列表<br>
	 * 只保留1小时
	 * 11/16 wilson fix , 新增以zoneid做區分, 用此來尋找有多少正在pending 等待登入的玩家
	 */
	/*private IShareMap<String, LoginVerifyInfo> loginVerifyCodeList = ServerGroup
			.getDataManager().getShareMap("LoginVerifyCodeList");*/

	private ConcurrentHashMap<String, ConcurrentHashMap<GUID, LoginVerifyInfo>> loginVerifyCodeList = new ConcurrentHashMap<String, ConcurrentHashMap<GUID, LoginVerifyInfo>>();
	
	/**
	 * 
	 */
	private static LoginVerifyCodeManager instance = new LoginVerifyCodeManager();

	/**
	 * 
	 */
	private LoginVerifyCodeManager() {
	}

	public static final LoginVerifyCodeManager getInstance() {
		return instance;
	}

	/**
	 * 建立 LoginVerifyInfo
	 * 
	 * @param userId player guid
	 * @param zoneId 目的 zoneId
	 * @param putLocalType <br>
	 *            CREATE_VERIFYCODE_NOT_PUT_LOCAL 僅建立<br>
	 *            CREATE_VERIFYCODE_PUT_LOCA 建立後自動放到本地清單中
	 * @return
	 */
	public LoginVerifyInfo createVerifyCode(GUID userId,
			String zoneId, int putLocalType) {
		// create code
		String code = GUIDFactory.genUniqueID(userId + "_" + zoneId);
		LoginVerifyInfo info = new LoginVerifyInfo();
		info.setUserId(userId);
		info.setDestZoneId(zoneId);
		info.setVerifyCode(code);
		
		// module name
		if(Contexts.getModule() != null)
		{
			info.setModuleName(Contexts.getModule().getModuleName());
		}
		
		// thread name
		info.setThreadName( Thread.currentThread().getName());
		
		if (putLocalType == CREATE_VERIFYCODE_PUT_LOCAL) {
			this.putVerifyCode(userId, info);
		}

		log.debug("createVerifyCode:" + info);
		return info;
	}

	/**
	 * 推出指定玩家的数据。数据也会被删除
	 * 
	 * @param userId
	 * @return
	 * 
	 * @author lipeilin
	 * @2011-3-22 下午06:36:26
	 */
	public LoginVerifyInfo pollCode(GUID userId, String zoneId) {
		
		if(userId == null || zoneId == null){
			return null;
		}
		
		ConcurrentHashMap<GUID, LoginVerifyInfo> playerVerifyMap = this.loginVerifyCodeList
				.get(zoneId);
		if (playerVerifyMap != null) {
			LoginVerifyInfo info = playerVerifyMap.get(userId);
			playerVerifyMap.remove(userId);
			return info;
		}
		return null;
	}

	/**
	 * 推出指定玩家的数据
	 * 
	 * @param userId
	 * @return
	 * 
	 * @author lipeilin
	 * @2011-3-22 下午06:36:26
	 */
	public LoginVerifyInfo getCode(GUID userId, String zoneId) {
		
		if(userId == null || zoneId == null){
			return null;
		}
		
		ConcurrentHashMap<GUID, LoginVerifyInfo> playerVerifyMap = this.loginVerifyCodeList.get(zoneId);
		//LoginVerifyInfo info = loginVerifyCodeList.get(userId);
		if(playerVerifyMap != null){
			LoginVerifyInfo info = playerVerifyMap.get(userId);
			return info;
		}
		return null;
	}

	/**
	 * 验证指定信息。 验证成功，则删除验证码
	 * 
	 * @param userId
	 * @param verifyCode
	 * @return
	 * 
	 * @author lipeilin
	 * @2011-3-22 下午06:40:38
	 */
	public LoginVerifyInfo verifyCode(GUID userId, String zoneId,
			String verifyCode) {
		
		if (userId == null || zoneId == null || verifyCode == null){
			return null;
		}

		ConcurrentHashMap<GUID, LoginVerifyInfo> playerVerifyMap = this.loginVerifyCodeList.get(zoneId);
		if(playerVerifyMap != null){
			LoginVerifyInfo info = playerVerifyMap.get(userId);
			
			log.debug("verifyCode! userId:"+userId+" zoneId:"+zoneId+" verifyCode:"+verifyCode+" info:"+info);
	
			if (info == null) {
				return null;
			}
	
			// 如验证码和zoneID的信息都正确，则是验证成功
			if (info.getVerifyCode().equals(verifyCode)
					&& info.getDestZoneId().equals(zoneId)
					&& info.getUserId().equals(userId)) {
				playerVerifyMap.remove(userId);
				return info;
			}
			else
			{
				log.error("verifyCode not correct! userId:"+userId+" zoneId:"+zoneId+" verifyCode:"+verifyCode+" info:"+info);
			}
		}
		return null;
	}

	/**
	 * 数量
	 * 
	 * @return
	 * 
	 * @author lipeilin
	 * @2011-3-22 下午06:49:52
	 */
	public int size() {
		return loginVerifyCodeList.size();
	}

	public long getLifespan() {
		return lifespan;
	}

	public void setLifespan(long lifespan) {
		this.lifespan = lifespan;
	}
	
	public void putVerifyCode(GUID userId, LoginVerifyInfo info) {
		if (info == null || info.getDestZoneId() == null)
			return;

		ConcurrentHashMap<GUID, LoginVerifyInfo> playerVerifyMap = this.loginVerifyCodeList
				.get(info.getDestZoneId());
		if (playerVerifyMap == null) {
			playerVerifyMap = new ConcurrentHashMap<GUID, LoginVerifyInfo>();
			this.loginVerifyCodeList.put(info.getDestZoneId(), playerVerifyMap);
		}
		info.setValidStartTime(System.currentTimeMillis());
		LoginVerifyInfo oldInfo = playerVerifyMap.put(userId, info);
		if(oldInfo != null)
		{
			//發生驗證碼覆蓋
			if (log.isInfoEnabled()) {
				log.info("verifyCode override! userId:"+userId+" oldInfo:" + oldInfo + " newInfo:"+info);
			}
		}
	}	
	
	public void removeVerifyCode(GUID userId, String zoneId) {
		if(userId == null || zoneId == null) return;
		ConcurrentHashMap<GUID, LoginVerifyInfo> playerVerifyMap = this.loginVerifyCodeList
				.get(zoneId);
		if(playerVerifyMap != null && playerVerifyMap.containsKey(userId)){
			playerVerifyMap.remove(userId);
		}
	}

	/**
	 * 取得等待進入中的玩家
	 * @param zoneId
	 * @return
	 */
	public int getPendingLoginPlayerAmount(String zoneId , GUID excludeId){
		int result = 0;
		
		if(zoneId == null)
		{
			return 0;
		}
		
		if(this.loginVerifyCodeList.containsKey(zoneId)){
			ConcurrentHashMap<GUID, LoginVerifyInfo> playerMap  = this.loginVerifyCodeList.get(zoneId);
			if(playerMap != null){
				if(excludeId == null || !playerMap.containsKey(excludeId))
					result = playerMap.size();
				else{
					result = playerMap.size() -1 ;
				}
			}
		}
		return result;
	}
	
	/**
	 * 發送認證法的msg給要去的zone
	 * @param info
	 */
	public boolean sendVerifyCodeNotifyMsg(int type, LoginVerifyInfo info,
			String moduleName, GUID sessionID) {
		if (info.getDestZoneId() == null) {
			return false;
		}
		GroupMessage gm = new GroupMessage();
		gm.setDestModuleID(info.getDestZoneId());
		gm.setMessageType(MessageTypes.S_LOGIN_VERIFYCODE_REQUEST);
		gm.setMessageContent(new VerifyInfoNotifyMsg(type, info, moduleName, sessionID));
		MessageAction.sendGroupMessage(gm);
		return true;
	}
	
	/**
	 * 回傳result
	 * 
	 * @param info
	 */
	public void sendVerifyCodeNotifyResponseMsg(VerifyInfoNotifyMsg info) {
		GroupMessage gm = new GroupMessage();
		String desId = info.getModuleName();
		gm.setDestModuleID(desId);
		gm.setMessageType(MessageTypes.S_LOGIN_VERIFYCODE_RESPONSE);
		gm.setMessageContent(info);
		MessageAction.sendGroupMessage(gm);
	}
	
	/**
	 * 移除特定zone上過期的登入請求
	 * @param zoneId
	 */
	public void removeExpireVerifyCode(String zoneId){
		
		if(zoneId == null)
		{
			return;
		}
		
		ConcurrentHashMap<GUID, LoginVerifyInfo> verifyMap = this.loginVerifyCodeList.get(zoneId);
		if(verifyMap != null){
			long currentTime = System.currentTimeMillis();
			Iterator<Entry<GUID, LoginVerifyInfo>> it  = verifyMap.entrySet().iterator();
			while(it.hasNext()){
				Entry<GUID, LoginVerifyInfo> entry = it.next();
				LoginVerifyInfo info= entry.getValue();
				if(info == null ||(currentTime - info.getValidStartTime() > this.lifespan)){
					it.remove();
				}
			}
		}
	}
}
